/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package edu.gatech.gellinservlet.model;

import java.util.ArrayList;
import java.util.Collections;
import java.io.*;
import java.io.Serializable;

/**
 * 
 * @author Tyler Powell
 */

public abstract class DataManager<E extends IDable> implements Serializable{
    
    private ArrayList<E> dataList;
    
    public DataManager()
    {
        dataList = new ArrayList<E>();
    }
    
    
    /**
     * Add data to the data manager.
     * @param data Data to add.
     */
    public void add(E data)
    {
        //TODO decide whether to check for redundant data
        dataList.add(data);
        //TODO decide if sort should only be called when actually displaying data
        sort();
    }
    
    /**
     * Remove the data from the data manager.
     * @param data Data to be removed.
     */
    public void remove(E data)
    {
        //TODO decide whether to use strict object comparison or a comparable
        //like this.data.equals(data)
        dataList.remove(data);
    }
    
    /**
     * Do a search for the data to be removed using an ID.
     * @param ID The identification code of the data.
     */
    public void remove(int ID)
    {
        E data = search(ID);
        remove(data);
    }
    
    /**
     * search the dataList for the criteria, returning first met object
     * @param criteria String search criteria
     * @return first satisfying object in list
     */
    public E search(String criteria)
    {
        for(E data : dataList)
        {
            if(criteria.equals(data.toString()))
            {
                return data;
            }
        }
        return null;
    }
    
    /**
     * Search the data manager for data containing the string criteria
     * @param criteria search using this string
     * @return an arraylist containing the results of the search
     */
    public ArrayList<E> searchList(String criteria)
    {
        ArrayList<E> results = new ArrayList();
        ArrayList<E> recursiveResults = new ArrayList();
        String dataString;
        String[] splitCriteria = criteria.split(" ");
        for(E data : dataList)
        {
            dataString = data.toString();
            if(dataString.contains(criteria))
            {
                results.add(data);
            }
        }
        //Two loops to add more relevant results first to ArrayList results
        //Less relevant, on word basis results.
        if(splitCriteria.length > 1) //base case, criteria of word length 1 has already been used
        {
            //gather all the objects that contain each word into one list
            for(String partialCriteria : splitCriteria)
            {
                recursiveResults = searchList(partialCriteria);
                
                //add the objects to the results list only if they are not already there
                for(E data : recursiveResults)
                {
                    if(!(results.contains(data)))
                    {
                        results.add(data);
                    }
                }
            }
        }
        return results;
    }
    
    
    /**
     * search for the data using its identification number
     * @param ID the identification number for the object
     * @return the object of type E represented by the ID number
     */
    public E search(int ID)
    {
        for(E data : dataList)
        {
            if(data.getID() == ID)
            {
                return data;
            }
        }
        //TODO throw error instead of return null when ID is not in list
        return null;
    }
    
    /**
     * Does a search on an external given datalist using the id.
     * @param ID the identification number for the object
     * @param dataList the external list to be searched
     * @return the object of type E represented by the ID number
     */
    public E searchExtern(int ID, ArrayList<E> dataList)
    {
        for(E data : dataList)
        {
            if(data.getID() == ID)
            {
                return data;
            }
        }
        //TODO throw error instead of return null when ID is not in list
        return null;
    }
    
    /**
     * Does a search on an external given datalist using string criteria
     * @param criteria what to search for in the list
     * @param dataList the external list to be searched
     * @return the object of type E represented by the String criteria
     */
    public E searchExtern(String criteria, ArrayList<E> dataList)
    {
        for(E data : dataList)
        {
            if(criteria.equals(data.toString()))
            {
                return data;
            }
        }
        return null;
    }
    
    
    /**
     * Sort the data alphabetically.
     */
    public void sort()
    {
        Collections.sort(dataList);
    }
    
    /**
     * Sort the data list by ID
     */
    public void sortByID()
    {
        //TODO write a sort by ID if necessary
    }
    
    public String toString()
    {
        String rep = "";
        for(Object data : dataList)
        {
            rep += ((E)data).toString() + "\n";
        }
        return rep;
    }
    
    public ArrayList<E> getDataList()
    {
        return dataList;
    }

    public void setDataList(ArrayList<E> dataList)
    {
        this.dataList = dataList;
    }
    
    
    
        /**
      * Save this object via serialization
      * 
      * @param filename the name of the file to save to
      */
//     public void save(String filename) {
//         try {
//             /*
//              * Create the object output stream for serialization.
//              * We are wrapping a FileOutputStream since we
//              * want to save to disk.  You can also save to socket
//              * streams or any other kind of stream.
//              */
//            ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(filename));
//            
//            /*
//             * The only real call we need.  The stream buffers the output and reuses
//             * data, so if you are serializing very frequently, then the object values might
//             * not actually change because the old serialized object is being reused.
//             * 
//             * To fix this you can try writeUnshared() or you can reset the stream.
//             * out.reset();
//             */
//            out.writeObject(this);
//            //out.writeObject(this.getDataList()); //this writes out the members, so we know that works
//        } catch (FileNotFoundException e) {
//            //myLogger.log(Level.SEVERE, "Save file not found: " + filename, e);
//        } catch (IOException e) {
//            //myLogger.log(Level.SEVERE, "General IO Error on saving: " + filename, e);
//        }
//         
//     }
//     
//     /**
//     * This is an example of a factory method
//     * We call this static method to create an
//     * instance of UserManager from a serialized file.
//     *
//     * @param filename the name of the file to use
//     * @return an instance of UserManager initialized from a file.
//     */
//     public static DataManager getFromFile(String filename) {
//         DataManager c = null;
//         try {
//             /*
//              * Create the input stream.  Since we want to read from the disk,
//              * we wrap a file stream.
//              */
//            ObjectInputStream in = new ObjectInputStream(new FileInputStream(filename));
//            /*
//             * Now we can read the entire company in with only one call
//             */
//            c = (DataManager) in.readObject();
//
//        } catch (FileNotFoundException e) {
//            //myLogger.log(Level.SEVERE, "Load file not found: " + filename, e);
//        } catch (IOException e) {
//            //myLogger.log(Level.SEVERE, "General IO Error on loading: " + filename, e);
//        } catch (ClassNotFoundException e) {
//            //myLogger.log(Level.SEVERE, "Company class not found on loading: " + filename, e);
//        }
//        return c;
//     }
}
